import cv2
import os
import json

gl_temp_dir = "./temp_result_dir"  # 默认的临时文件夹，默认将生成的切片存入其中
gl_img_info_file = "info.txt"  # 图像信息数据存于此处


def __creat_dir(result):
    """
    若目录不存在则创建目录
    :param result: 要创建的目录的名字
    """
    if not os.path.exists(result):
        os.mkdir(result)


def __generate_file_name(end_with, *args):
    """
    根据传入的参数生成文件名称字符串 形如 a_b_c_d.bmp
    :param args:组成文件名称的参数
    :param end_with:文件后缀
    :return:完整的文件名字
    """
    name_str = str(args[0])
    for i in range(1, len(args)):
        name_str = name_str + "_" + str(args[i])
    name_str = name_str + end_with
    return name_str


def __write_basic_info_to_file(img, clip_w_pixels, clip_h_pixels, step_w, step_h, total_clip_num, clip_type):
    """
    这个函数用于将分割后图像的数据写入info.txt文件中去，方便合并时从中读取对应的所需参数
    :param img: 原始图像，其本身不写入，此处的传入是为了得到原始图像的基本信息
    :param clip_w_pixels: 切片宽度像素数目
    :param clip_h_pixels: 切片高度像素数目
    :param step_w: 横向步长
    :param step_h: 纵向步长
    :param total_clip_num: 最后生成的总的切片数目
    :param clip_type: 切片存储的类型
    """

    # 建立对应信息的字典，用于生成对应的json字符串
    img_info = {"img_h": img.shape[0], "img_w": img.shape[1], "img_c": img.shape[2],
                "clip_w_pixels": clip_w_pixels, "clip_h_pixels": clip_h_pixels, "step_w": step_w,
                "step_h": step_h, "total_clip_num": total_clip_num, "clip_type": clip_type}
    # 打开文件info.txt
    info_file = open("%s\\%s" % (gl_temp_dir, gl_img_info_file), 'w')
    # 生成json
    temp_content = json.dumps(img_info)
    # 计算json的字节长度，并首先第一行写入
    basic_info_len = len(temp_content.encode())
    info_file.write("%s\n" % basic_info_len)
    # 写入json到文件
    info_file.write(temp_content)
    info_file.flush()
    info_file.close()


def img_cut(img, clip_w_pixels, clip_h_pixels, step_w, step_h, result_dir=None, clip_file_type=".bmp"):
    """
    将是原始图像按照给定参数分割成单张小图像，并将其保存至默认目录
    :param clip_file_type: 切片后的小图像的存储类型 默认为bmp格式
    :param img: 原始图像
    :param clip_w_pixels: 单张切片的宽度像素数目
    :param clip_h_pixels: 单张切片的高度像素数目
    :param step_w: 滑动窗口的横向步长
    :param step_h: 滑动窗口的纵向步长
    :param result_dir: 分割后的结果的存放目录，为None则使用默认值
    """
    # img[clip_top:clip_bottom, clip_left:clip_right]
    if img is not None:
        # 根据传入的参数是否为空来选择是使用默认路径还是外部指定的路径
        if result_dir is not None:
            __creat_dir(result_dir)  # 建立临时文件夹
        else:
            __creat_dir(gl_temp_dir)
        # 初始化临时参数
        img_h, img_w, clip_top, clip_bottom, clip_left, clip_right = img.shape[0], img.shape[
            1], 0, clip_h_pixels, 0, clip_w_pixels
        total_clips = 0  # 用于统计最后一共切割获得了多少张图像
        while True:
            clip_left, clip_right = 0, clip_w_pixels  # 本次切片的左边界，右边界
            while True:
                # 生成切片临时图像，并且以切片位置信息为参数生成图像的名称写入外存
                temp_img = img[clip_top:clip_bottom, clip_left:clip_right]
                # 生成本张切片的文件名
                img_name = __generate_file_name(clip_file_type, clip_top, clip_bottom, clip_left, clip_right)
                # 写入对应文件夹中
                cv2.imwrite("%s\\%s" % (gl_temp_dir, img_name), temp_img)
                total_clips = total_clips + 1  # 切片总数加一
                if clip_right == img_w:
                    break  # 当到达图像右边界时结束循环
                clip_left = clip_left + step_w  # 更新切片左右边界
                clip_right = clip_right + step_w
                # 防止右边界超出原图像的大小范围，即切片的最后一张的大小可能会小于clip_w_pixels要求的大小
                if clip_right > img_w:
                    clip_right = img_w
            if clip_bottom == img_h:
                break  # 当到达图像底部时结束循环
            clip_top = clip_top + step_h  # 更新切片上下边界
            clip_bottom = clip_bottom + step_h
            # 与左右边界同理，防止下边界超出原图像的大小范围
            if clip_bottom > img_h:
                clip_bottom = img_h
        # 在所有切片切割完成时，将全部信息写入info.txt中
        __write_basic_info_to_file(img, clip_w_pixels,
                                   clip_h_pixels, step_w,
                                   step_h, total_clips, clip_file_type)
